<template>
  <div class="m7-select" v-loadmore="loadMore" v-clickoutside="handleClickOutside">
    <el-popover
      ref="popover4"
      placement="bottom"
      :width="inputWidth || 190"
      :disabled="disabled"
      @show="popoverShow"
      v-model="visible"
      v-show="visible"
      transition=""
      @after-leave="popoverHide"
      :popper-class=" multiple ? 'el-select-dropdown is-multiple padding-no' : 'el-select-dropdown padding-no'"
      trigger="click">
      <ul class="el-select-dropdown__list">
        <li
          class="el-select-dropdown__item"
          v-for="(item, index) in optionsArrShow"
          :key="index"
          @click="nodeClick(item)"
          :class="{ selected: item.select, 'is-disabled': item.disabled }"
          v-show="item.visible">
          {{ item.label }}
        </li>
        <li v-if="optionsArrShow.length === 0" class="el-select-dropdown__empty">
          {{ emptyText }}
        </li>
      </ul>
    </el-popover>
    <div class="el-select el-select--mini">
      <div v-popover:popover4 @click="inputClick">
        <div class="el-select__tags tag-input" v-if="multiple" :style="{ 'max-width': inputWidth - 32 + 'px' }">
          <el-tag
            class="tag"
            v-if="value && value.length"
            size="mini"
            type="info"
            :closable="!disabled"
            @close="close">
            <span class="el-select__tags-text tag-max">{{ tagName }}</span>
          </el-tag>
          <el-tag type="info" size="mini" v-if="value && value.length > 1">+{{ value.length - 1 }}</el-tag>
          <input
            type="text"
            v-if="filterable"
            autocomplete="off"
            class="el-select__input is-mini"
            @focus="focus"
            @blur="blur"
            :style="{ width: mulitInputwidth + 'px' }"
            ref="input"
            v-model="query" />
        </div>
        <el-input
          v-if="multiple"
          ref="reference"
          v-model="noquery"
          type="text"
          :placeholder="cachedPlaceHolder"
          :auto-complete="'off'"
          :size="size"
          :validate-event="false"
          :disabled="disabled"
          :readonly="true"
          :class="{ 'is-focus': visible, 'is-label': palaceHolderStyle }">
          <template slot="prefix" v-if="$slots.prefix">
            <slot name="prefix"></slot>
          </template>
          <i slot="suffix" :class="[ 'el-select__caret', 'el-input__icon', 'el-icon-arrow-up', iconClass ]"></i>
        </el-input>
        <el-input
          v-if="!multiple"
          ref="reference"
          v-model="query"
          type="text"
          :placeholder="cachedPlaceHolder"
          :auto-complete="'off'"
          :size="size"
          :validate-event="false"
          :disabled="disabled"
          :readonly="readonly"
          :class="{ 'is-focus': visible, 'is-label': palaceHolderStyle }">
          <template slot="prefix" v-if="$slots.prefix">
            <slot name="prefix"></slot>
          </template>
          <template slot="suffix" v-if="isShowUpIcon">
            <i v-show="!showClose" :class="[ 'el-select__caret', 'el-input__icon', 'el-icon-arrow-up', iconClass ]"></i>
            <i v-if="showClose" class="el-select__caret el-input__icon el-icon-circle-close" @click="handleClearClick" ></i>
          </template>
        </el-input>
      </div>
    </div>
  </div>
</template>

<script lang="ts">
// 如果新增还是+1的形式，只是select编辑回显，又被disabled类型的，无法看全配置项的，可以选择使用另一个selectEcho.vue组件
import { Component, Prop, Watch, Mixins } from 'vue-property-decorator'
import isEqual from 'lodash/isEqual'
import Emitter from './emitter'
import { addResizeListener, removeResizeListener } from './resize-event'
import Clickoutside from 'element-ui/src/utils/clickoutside'
@Component({
  name: 'm7Select',
  directives: {
    loadmore: {
      bind (el, binding) {
        const SELECTWRAP_DOM: any = el.querySelector('.el-select-dropdown__list')
        SELECTWRAP_DOM.addEventListener('scroll', () => {
          const CONDITION = SELECTWRAP_DOM.scrollHeight - SELECTWRAP_DOM.scrollTop <= (SELECTWRAP_DOM.clientHeight + 50)
          if (CONDITION) {
            binding.value()
          }
        })
      }
    },
    Clickoutside
  }
})
export default class M7Select extends Mixins(Emitter) {
  @Prop(String) public name !: ''
  @Prop(String) public id !: ''
  @Prop() public value !: {
    required: true
  }

  @Prop({ type: Boolean, default: () => true }) public isShowUpIcon
  @Prop({ default: () => 'off' }) public autoComplete?: ''
  @Prop(Boolean) public automaticDropdown: boolean|undefined
  @Prop(String) public size: string|undefined
  @Prop(Boolean) public disabled: boolean|undefined
  @Prop(Boolean) public clearable: boolean|undefined
  @Prop({ default: () => false }) public remoteLoading: boolean|undefined
  @Prop(Boolean) public filterable: boolean|undefined
  @Prop(Boolean) public allowCreate: boolean|undefined
  @Prop(Boolean) public loading: boolean|undefined
  @Prop(String) public popperClass: string|undefined
  @Prop(Boolean) public remote: boolean|undefined
  @Prop(String) public loadingText: string|undefined
  @Prop(String) public noMatchText: string|undefined
  @Prop(String) public noDataText: string|undefined
  @Prop(Function) public remoteMethod: any
  @Prop(Function) public filterMethod: any
  @Prop() public row: any
  @Prop(Boolean) public multiple: boolean|undefined
  @Prop({ type: Number, default: () => 0 }) public multipleLimit: number|undefined
  @Prop({ type: String, default: () => '请选择' }) public placeholder: string|undefined
  @Prop(Boolean) public defaultFirstOption: boolean|undefined
  @Prop(Boolean) public reserveKeyword: boolean|undefined
  @Prop({ type: String, default: () => 'value' }) public valueKey: string|undefined
  @Prop(Boolean) public collapseTags: boolean|undefined
  @Prop({ type: Boolean, default: () => true }) public popperAppendToBody: boolean|undefined
  @Prop({
    type: Object,
    default: () => {
      return { label: 'label', value: 'value' }
    }
  }) public defaultProps: any

  @Prop({
    type: Array,
    default: () => {
      const arr: any = []
      for (let i = 0; i < 5000; i++) {
        arr.push({ label: i + 'x', value: i + 'x' })
      }
      return arr
    }
  }) public options: any

  private tagName = ''

  private visible = false

  private query = ''

  private noquery = '' // 多选时占位

  private maxIndex = 100

  private inputWidth = 0

  private timer: any = ''

  private timera: any = ''

  get cachedPlaceHolder () {
    if (this.multiple) {
      return (((this as any).value && (this as any).value.length) || this.query) ? '' : this.placeholder
    } else {
      return this.tagName || this.placeholder
    }
  }

  get emptyText () {
    if (this.remoteLoading) {
      return '数据加载中...'
    } else {
      return '无匹配数据'
    }
  }

  get palaceHolderStyle () {
    if (this.multiple) {
      return (this as any).value && (this as any).value.length > 0
    } else {
      return this.tagName
    }
  }

  // eslint-disable-next-line vue/return-in-computed-property
  get mulitInputwidth () {
    const self: any = this
    if (self.multiple) {
      if (!(self.value && self.value.length)) {
        return self.inputWidth - 40
      } else if (self.value && self.value.length === 1) {
        return self.inputWidth - 125
      }
      return self.inputWidth - 155
    }
  }

  get tagId () {
    if (this.multiple) {
      return this.value && this.value[0]
    } else {
      return this.value
    }
  }

  get optionsArr () {
    const label = this.defaultProps.label
    const value = this.defaultProps.value
    const options = this.options
    const self: any = this
    return options.map((item: any) => {
      let select = false
      if (self.multiple) {
        select = self.value && self.value.some((one: any) => one === item[value])
      } else {
        select = self.value === item[value]
      }
      let visible = true
      if (self.query && item[label] && item[label].indexOf(self.query) === -1) {
        visible = false
      }
      return { label: item[label], value: item[value], visible, select, disabled: item.disabled }
    })
  }

  get optionsArrShow () {
    const optionsArr = this.optionsArr
    return optionsArr.filter((item: any, index: number) => {
      if (index < this.maxIndex && item.visible) {
        return true
      }
    })
  }

  get readonly () {
    // trade-off for IE input readonly problem: https://github.com/ElemeFE/element/issues/10403
    const isIE = !this.$isServer && !isNaN(Number(document.DOCUMENT_NODE))
    // eslint-disable-next-line no-mixed-operators
    return !this.filterable || this.multiple || !isIE && !this.visible
  }

  get iconClass () {
    return this.visible ? 'is-reverse ' : ''
  }

  get showClose () {
    const hasValue = this.multiple
      ? Array.isArray(this.value) && this.value.length > 0
      : this.value !== undefined && this.value !== null && JSON.parse(JSON.stringify(this.value)) !== ''
    const criteria = this.clearable && hasValue
    return criteria
  }

  @Watch('tagId')
  private tagIdChange (val: any) {
    this.getTagName(val)
  }

  @Watch('visble')
  private visibleChange (val: any) {
    this.$emit('visible-change', val)
  }

  // 分批加载
  private handler () {
    this.maxIndex = 100
    window.clearInterval(this.timer)
    this.timer = window.setInterval(() => {
      this.maxIndex += 200
      if (this.maxIndex > this.options.length) {
        window.clearInterval(this.timer)
      }
    }, 10)
  }

  private nodeClick (item: any) {
    if (item.disabled) {
      return
    }
    if (this.multiple) {
      if (this.$refs.input) {
        (this as any).$refs.input.focus()
      }
      this.query = ''
      const value = JSON.parse(JSON.stringify(this.value))
      const index = value.indexOf(item.value)
      if (index !== -1) {
        value.splice(index, 1)
      } else {
        value.push(item.value)
      }
      this.$emit('input', value)
      this.emitChange(value)
    } else {
      // 单选
      this.visible = false
      this.query = ''
      this.$emit('input', item.value)
      this.$emit('nodeClick', item.value, this.row)
      this.emitChange(item.value)
    }
  }

  private getTagName (val: any) {
    this.tagName = ''
    if (val !== undefined) {
      const self = this
      this.optionsArr.some((item: any) => {
        if (item.value === val) {
          self.tagName = item.label
        }
      })
    }
  }

  private blur () {
    console.log('blur')
  }

  private focus () {
    console.log('focus')
  }

  private handleClearClick (event: any) {
    this.deleteSelected(event)
  }

  private deleteSelected (event: any) {
    console.log(event)
    event.stopPropagation();
    const value = this.multiple ? [] : '';
    this.$emit('input', value);
    this.emitChange(value);
    this.visible = false;
    this.$emit('clear');
    this.$emit('nodeClear', '', this.row)
  }

  private close () {
    if ((this as any).value && (this as any).value.length) {
      const value = JSON.parse(JSON.stringify(this.value))
      this.$emit('input', value.slice(1))
    }
  }

  private emitChange (val: any) {
    if (!isEqual(this.value, val)) {
      this.$emit('change', val, arguments[1])
      this.dispatchEmitter('ElFormItem', 'el.form.change', val)
    }
  }

  private handleClickOutside () {
    // this.$nextTick(() => {
    //   this.query = ''
    //   this.maxIndex = 100
    //   this.timera = window.setInterval(() => {
    //     this.maxIndex += 200
    //     if (this.maxIndex > this.options.length) {
    //       this.visible = false
    //       window.clearInterval(this.timera)
    //     }
    //   }, 10)
    //   window.clearInterval(this.timera)
    // })
  }

  private inputClick () {
    if (this.disabled) {
      return
    }
    if (this.$refs.input) {
      (this as any).$refs.input.focus()
    }
  }

  private popoverShow () {
    this.$nextTick(() => {
      this.handler()
    })
  }

  private popoverHide () {
    if (this.$refs.input) {
      (this as any).$refs.input.blur()
    }
    this.$nextTick(() => {
      this.query = ''
      this.maxIndex = 100
      window.clearInterval(this.timer)
    })
  }

  private resetInputWidth () {
    this.inputWidth = (this as any).$refs.reference.$el.getBoundingClientRect().width
  }

  private mounted () {
    this.getTagName(this.tagId)
    this.$nextTick(() => {
      addResizeListener(this.$el, this.resetInputWidth)
      if (this.$refs.reference && (this as any).$refs.reference.$el) {
        this.resetInputWidth()
      }
    })
  }

  private created () {
    if (this.multiple && !Array.isArray(this.value)) {
      this.$emit('input', [])
    }
    if (!this.multiple && Array.isArray(this.value)) {
      this.$emit('input', '')
    }
    this.$on('fieldReset', () => {
      this.dispatchEmitter('ElFormItem', 'el.form.change')
    })
  }

  private beforeDestroy () {
    window.clearInterval(this.timer)
    if (this.$el && this.resetInputWidth) {
      removeResizeListener(this.$el, this.resetInputWidth)
    }
  }

  private loadMore () {
    this.$emit('loadMore')
  }

  @Watch('options')
  private watchOptions () {
    let value
    if (this.multiple) {
      value = this.value && this.value[0]
    } else {
      value = this.value
    }
    this.getTagName(value)
  }

  // @Watch('value')
  // private watchValue (newValue) {
  //   this.getTagName(newValue)
  // }

  @Watch('query')
  private watchQuery (newQuery: any) {
    if (this.remote) {
      this.$emit('remoteMethod', newQuery)
    }
  }
}
</script>
<style lang="stylus">
.padding-no
  padding 0
.m7-select
  .is-label
    input::-webkit-input-placeholder
      color #606266 !important
  .el-select .el-tag__close.el-icon-close
    top 1px
</style>
<style scoped lang="stylus">
@import '../../common/style/base.styl'
.m7-select
  display inline-block
  width 100%
  &:hover
    cursor pointer
.el-select-dropdown__item
  padding 0px 25px 0px 20px
.el-select
  width 100%
  box-sizing border-box
// 覆盖ele升级得样式
.el-select .el-select__tags>span
  display flex
.tag
  display flex
  align-items center
.tag-input
  width calc(100% - 20px)
  display flex
  flex-direction row
  flex-wrap nowrap
  justify-content left
.tag-max
  max-width 60px
  display inline-block
  text-overflow ellipsis
  overflow hidden
  white-space nowrap
.el-select__input
  width 20px
  padding-left 10px
.el-select-dropdown__list
  max-height 260px
  overflow-y auto
</style>
